package org.oaix.utils;

import org.apache.commons.lang3.StringUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;


public class GZUtils {
	/**
	 * 使用gzip压缩字符串
	 *
	 * @param str 要压缩的字符串
	 * @return
	 */
	public static String compress(String str) {
		if (str == null || str.length() == 0) {
			return str;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		GZIPOutputStream gzip = null;
		try {
			gzip = new GZIPOutputStream(out);
			gzip.write(str.getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (gzip != null) {
				try {
					gzip.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return new BASE64Encoder().encode(out.toByteArray());
	}

	/**
	 * 使用gzip解压缩
	 *
	 * @param compressedStr 压缩字符串
	 * @return
	 */
	public static String uncompress(String compressedStr) {
		if (compressedStr == null) {
			return null;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ByteArrayInputStream in = null;
		GZIPInputStream ginzip = null;
		byte[] compressed = null;
		String decompressed = null;
		try {
			compressed = new BASE64Decoder().decodeBuffer(compressedStr);
			in = new ByteArrayInputStream(compressed);
			ginzip = new GZIPInputStream(in);
			byte[] buffer = new byte[1024];
			int offset = -1;
			while ((offset = ginzip.read(buffer)) != -1) {
				out.write(buffer, 0, offset);
			}
			decompressed = out.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (ginzip != null) {
					ginzip.close();
				}
				if (in != null) {
					in.close();
				}
				out.close();
			} catch (IOException ignored) {
			}
		}
		return decompressed;
	}

	/**
	 * long数组转化为byte数组
	 *
	 * @param longArray
	 * @return
	 */
	public static byte[] longToByte(long[] longArray) {
		if (longArray==null||longArray.length==0){
			return new byte[]{};
		}
		byte[] byteArray = new byte[longArray.length * 8];
		for (int i = 0; i < longArray.length; i++) {
			byteArray[8 * i] = (byte) (longArray[i] >> 56);
			byteArray[1 + 8 * i] = (byte) (longArray[i] >> 48);
			byteArray[2 + 8 * i] = (byte) (longArray[i] >> 40);
			byteArray[3 + 8 * i] = (byte) (longArray[i] >> 32);
			byteArray[4 + 8 * i] = (byte) (longArray[i] >> 24);
			byteArray[5 + 8 * i] = (byte) (longArray[i] >> 16);
			byteArray[6 + 8 * i] = (byte) (longArray[i] >> 8);
			byteArray[7 + 8 * i] = (byte) (longArray[i]);
		}
		return byteArray;
	}

	/**
	 * byte数组转化为long数组
	 * @param byteArray
	 * @return
	 * @throws IOException
	 */
	public static long[] byteToLong(byte[] byteArray)  {
		if (byteArray==null||byteArray.length==0){
			return null;
		}
		long[] longArray = new long[byteArray.length / 8];
		for (int i = 0; i < longArray.length; i++) {
			longArray[i] = (((long) byteArray[8 * i] & 0xff) << 56)
					| (((long) byteArray[1 + 8 * i] & 0xff) << 48)
					| (((long) byteArray[2 + 8 * i] & 0xff) << 40)
					| (((long) byteArray[3 + 8 * i] & 0xff) << 32)
					| (((long) byteArray[4 + 8 * i] & 0xff) << 24)
					| (((long) byteArray[5 + 8 * i] & 0xff) << 16)
					| (((long) byteArray[6 + 8 * i] & 0xff) << 8)
					| (((long) byteArray[7 + 8 * i] & 0xff));

		}
		return longArray;
	}

	/**
	 * 使用gzip解压缩
	 * 数组压缩
	 *
	 * @param data
	 * @return
	 */
	public static byte[] compress(byte[] data) {
		if (data==null||data.length==0){
			return new byte[]{};
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		GZIPOutputStream gzip = null;
		try {
			gzip = new GZIPOutputStream(out);
			gzip.write(data);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (gzip != null) {
				try {
					gzip.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return out.toByteArray();
	}

	/**
	 * 使用gzip解压缩
	 *
	 * @param data 压缩数组
	 * @return
	 */
	public static byte[] uncompress(byte[] data) {
		if (data==null||data.length==0){
			return new byte[]{};
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ByteArrayInputStream in = null;
		GZIPInputStream ginzip = null;
		byte[] decompressed = null;
		try {
			in = new ByteArrayInputStream(data);
			ginzip = new GZIPInputStream(in);
			byte[] buffer = new byte[1024];
			int offset = -1;
			while ((offset = ginzip.read(buffer)) != -1) {
				out.write(buffer, 0, offset);
			}
			decompressed = out.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (ginzip != null) {
					ginzip.close();
				}
				if (in != null) {
					in.close();
				}
				out.close();
			} catch (IOException ignored) {
			}
		}
		return decompressed;
	}

	/**
	 * Long列表 gz压缩成base64
	 * @param data
	 * @return
	 */
	public static String compressLongListToBase64(List<Long> data){
		if (data==null||data.isEmpty()){
			return "";
		}
		byte[] byteData=GZUtils.longToByte(data.stream().mapToLong(id->id).toArray());
		byte[] gzData=GZUtils.compress(byteData);
		return new String(new BASE64Encoder().encode(gzData).getBytes(), StandardCharsets.ISO_8859_1);
	}

	/**
	 * base64 gz解压成 Long列表
	 * @param base64
	 * @return
	 */
	public static List<Long> uncompressBase64ToLongList(String base64){
		if (StringUtils.isBlank(base64)){
			return Collections.emptyList();
		}
		List<Long> data;
		try {
			byte[] base64Data=new BASE64Decoder().decodeBuffer(base64);
			byte[] byteData=GZUtils.uncompress(base64Data);
			long[] longArr = GZUtils.byteToLong(byteData);
			data= new ArrayList<>(longArr.length);
			for (long num:longArr){
				data.add(num);
			}
		} catch (IOException e) {
			e.printStackTrace();
			data= Collections.emptyList();
		}
		return data;
	}

}
